package com.autumn.platform.dao.expression.impl;

import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.session.Configuration;

import com.autumn.platform.core.spring.SpEL;
import com.autumn.platform.dao.expression.IExpressionHandler;

public class SpELExpressionHandler implements IExpressionHandler {

    /**
     * 直接返回true，也就是说不做进一步判断，支持所有的${(exp)}、#{(exp)}内的表达式 由于支持所有表达式，实际上起到了一种拦截作用，所以需要注意，注册该实现时必须最低优先级
     */
    @Override
    public boolean supports(String expression, Configuration configuration) {
        return true;
    }

    /**
     * 对SqlMapper配置中的表达式求值
     */
    @Override
    public Object eval(String expression, Object parameter, Configuration configuration) {
        String databaseId = configuration.getDatabaseId();
        /**
         * 如果以spel:为前缀，则将mybatis包装后的参数、数据库id以及表达式自身一起封装一个新的root对象
         * 因此在exp表达式中可以通过params.paramName、databaseId等形式访问
         */
        if (expression.toLowerCase().startsWith("spel:")) {
            expression = expression.substring(5);
            Root root = new Root(parameter, databaseId, expression);
            return SpEL.getValue(root, expression);
        }
        /**
         * 否则将databaseId作为一个特殊名称的变量 因此在exp表达式中可以通过paramName、#databaseId等形式访问
         */
        else {
            Map<String, Object> vars = new HashMap<String, Object>();
            vars.put("databaseId", databaseId);
            return SpEL.getValue(parameter, expression, vars);
        }
    }

    public static class Root {

        private final Object params;
        private final String databaseId;
        private final String expression;

        public Root(Object params, String databaseId, String expression) {
            this.params = params;
            this.databaseId = databaseId;
            this.expression = expression;
        }

        public Object getParams() {
            return params;
        }

        public String getDatabaseId() {
            return databaseId;
        }

        public String getExpression() {
            return expression;
        }
    }
}
